// This file is part of SyncStar, free software released under GPL v2.
package com.syncstar;

import android.content.Context;
import android.util.Log;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/** Utility class for handling SSL (https://) connections. */
class SslUtils {
  private static final String TAG = SmsUtils.class.getSimpleName();

  private static SSLSocketFactory originalDefaultSslSocketFactory_;
  private static SSLSocketFactory permissiveDefaultSslSocketFactory_;
  private static boolean isPermissive_;
  static private Lock permissiveLock_ = new ReentrantLock();

  static {
    isPermissive_ = false;
    originalDefaultSslSocketFactory_ = HttpsURLConnection.getDefaultSSLSocketFactory();
    // Based on: http://stackoverflow.com/questions/3761737/
    // https-get-ssl-with-android-and-self-signed-server-certificate/4008166#4008166
    SSLContext ctx;
    try {
      ctx = SSLContext.getInstance("TLS");
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException("no TLS", e);
    }
    try {
      ctx.init(null, new TrustManager[] {
        new X509TrustManager() {
          public void checkClientTrusted(X509Certificate[] chain, String authType) {}
          public void checkServerTrusted(X509Certificate[] chain, String authType) {}
          public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
        }
      }, null);
    } catch (KeyManagementException e) {
      throw new RuntimeException("new trust manager", e);
    }
    // TODO: Consider an alternative of adding some certificates of some
    // specific servers. Try these:
    // http://stackoverflow.com/questions/4461360/how-to-install-trusted-ca-certificate-on-android-device
    // http://stackoverflow.com/questions/5256356/adding-ssl-certificate-to-keystore
    permissiveDefaultSslSocketFactory_ = ctx.getSocketFactory();
  }

  static void setPermissiveSslCertificateVerification(boolean isPermissive) {
    permissiveLock_.lock();
    try {
      // TODO: Add automatic propagation to ConfigActivity.
      Log.e(TAG, "CONNX setcert oldPermissive=" + isPermissive_ + " isPermissive=" + isPermissive);
      isPermissive_ = isPermissive;  // TODO: Protect against race conditions.
      HttpsURLConnection.setDefaultSSLSocketFactory(
          isPermissive ?
          permissiveDefaultSslSocketFactory_ : originalDefaultSslSocketFactory_);
    } finally {
      permissiveLock_.unlock();
    }
  }

  static void setupPermissiveSslCertificateVerification(Context context) {
    setPermissiveSslCertificateVerification(
        context.getSharedPreferences("config", 0).getBoolean("permissive_ssl", false));
  }
}
